#ifndef __LICH_CONFIGURE_H__
#define __LICH_CONFIGURE_H__

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

// {{ feature on/off

#define ENABLE_QOS 0

#define ENABLE_QOS_VOL 1

#define ENABLE_VAAI 1

#define ENABLE_LOCAL_RPC 1

#define ENABLE_HEARTBEAT 1

#define ENABLE_ISCSI_CACHE_REUSE 0
#define ENABLE_ISCSI_IPV6 1

#define ENABLE_ALIGN_NEW 1

/* connot open this for now, hazard writefailure, maybe no problem with bit lock */
#define ENABLE_CHUNK_PARALLEL 0
#define CHOOSE_NEWEST_CHUNK FALSE

#define ENABLE_SNAP_ROLLBACK_OPTIMIZE 1

#define ENABLE_SNAP_CONTEXT 0

#define ENABLE_SNAP_FIX_VERSION 1

#define ENABLE_TRANS_CREATE_SNAPSHOT 1

#define ENABLE_LARGE_VOLUME 0

#define ENABLE_BALANCE 1

#define ENABLE_CREATE_BALANCE 0

#define ENABLE_VM_MEM_PRIVATE 0

#define ENABLE_VFM 1

#define USE_ROW2    1

#define ENABLE_ANALYSIS 1

#define ENABLE_HUGE_MALLOC 1

#define ENABLE_HUGE_RING 1

#define ENABLE_REPLICA_FALLBACK 0

#define ENABLE_ETCD_CONN 0

/**
 * @todo cannot set 1
 */
#define ENABLE_REPLICA_GC 0

#define ENABLE_RECOVERY_DEEP 0

#define ENABLE_TCP_THREAD 0

#define ENABLE_REDIS_CACHE 0

#define ENABLE_START_PARALLEL 1

#define ENABLE_SCHEDULE_RUN 0

#define CHUNK_UNINTACT_VFM 1

// LSV
#define ENABLE_LSV 1
#define LSV 1

//ec
#define ENABLE_EC 0
#if ENABLE_EC
#define ECLOG_ENABLE    1
#endif

/**
 * if define USE_HUGEPAGE, core file maybe cannot debug with gdb.
 * so, if coredumped and core file cannot debug,please undefine this macro
 */

// }}

// {{

#define RECOVERY_RPC_TIMEOUT (30)

// }}

// debug check on/off
// {{

#define ENABLE_DEBUG_MODE 0

#define ENABLE_SCHEDULE_LOCK_CHECK 0
#define ENABLE_SCHEDULE_CHECK_RUNTIME 0
#define ENABLE_SCHEDULE_STACK_ASSERT 1
#define ENABLE_SCHEDULE_DEBUG 0
#define ENABLE_SCHEDULE_SELF_DEBUG 0
#define ENABLE_LOCK_DEBUG 0

#define ENABLE_ETCD_DBUG TRUE

#define ENABLE_BMAP_DEBUG FALSE

/**
 * for io analysis
 *
 * 全历史分析法：只有跟踪一个对象完整的生命周期变化，才能在发生错误时，精确定位现象所以产生的根本原因。
 *
 * 知道存在问题是第一步，更重要的是定位产生问题的根源。
 */
#define ISCSI_IO_RECORD         0

#define ISCSI_CMD_RECORD        0

/**
 * 可以记录每次io到/dev/可以记录每次io到/dev/shm/lich4/ramdisk/vol.xx.0文件下。
 * 读取的时候进行对比。发现不一致则打印日志。用来调试写错误。
 * 所以需要测试的卷不能太大。否则容易引起/目录没有空间。
 *
 * 将每次io内容写入/dev/shm/ramdisk文件中。一个io记录两次: vol和raw数据.
 * 所以集群所有卷的总大小不能大于/dev/shm大小的一半。
 * 将每次io的crc记录到日志文件。每512字节一个crc.
 * 日志文件：/opt/fusionstack/log/ramdisk.log
 */
#define ENABLE_RAMDISK      FALSE

/**
 * 将chunk的每sync recovery check等状态变化信息打印在日志
 */
#define ENABLE_CHUNK_DEBUG  FALSE

/**
 * 跟踪一个函数的多阶段执行性能
 */
#define ENABLE_PROFILE   0

// }}

#define MAXSIZE 256
#define MAX_VIP_NUM 32
#define MAX_VIP_LEN 64

//to be compitable with spdk.
#ifndef likely
#define likely(x)       __builtin_expect(!!(x), 1)
#endif

#ifndef unlikely
#define unlikely(x)     __builtin_expect(!!(x), 0)
#endif

#ifndef IN
#define IN
#endif
#ifndef INOUT
#define INOUT
#endif
#ifndef OUT
#define OUT
#endif

enum value_type {
        V_STATE,
        V_NUMBER,
        V_STRING,
};

struct nfsconf_export_t
{
        char path[MAXSIZE];
        char ip[16];
        char permision[MAXSIZE];
};

#define  MAX_NET_COUNT 12

typedef struct {
        int count;
        struct {
                uint32_t network;
                uint32_t mask;
        } network[MAX_NET_COUNT];
} netconf_t;

/* nfs configure */
struct nfsconf_t
{
        int use_export;
        int export_size;
        int rsize;
        int wsize;
        struct nfsconf_export_t nfs_export[1024];
};

typedef struct iscsivip
{
        int vip_count;
        char vip[MAX_VIP_NUM][MAX_VIP_LEN];
} iscsi_vip_t;

/* iscsi configure */
struct sanconf_t
{
        char iqn[MAXSIZE];
        int lun_blk_shift;
        int iscsi_gateway;
        uint16_t iscsi_port;
        iscsi_vip_t iscsi_vip;
        char ucarp_vip[MAXSIZE];
        int iscsi_timeout;
        int iser;
        int tcp_discovery;
};

/* web configure */
struct webconf_t
{
    int webport;
    int use_ratelimit;
};

/* mds configure */
struct mdsconf_t
{
        int meta;
};

/* cds configure */
struct cdsconf_t
{
        int disk_timeout;
        int ha_mode;
        uint64_t disk_keep;

        /* cache config */
        // @feature SSD Cache, 0-100，表示ssd上cache占用的百分比
        int disk_cache;
        int cache_flush;
};

struct logconf_t
{
        int log_libylib;
        int log_libynet;
        int log_libcluster;
        int log_libstorage;
        int log_libinterface;
};

/* global configure */
struct gloconf_t
{
        char cluster_name[MAXSIZE];
        char uuid[MAXSIZE];
        char home[512];
        int kv_redis;
        int bmap_mem;
        int cluster_id;

        int wmem_max;
        int rmem_max;
        int maxcore;
        int coredump;

        int restart;
        int testing;
        int backtrace;
        int solomode;
        int cache_type;
        int cache_enable;
        int nohosts;
        int rdma;
        int rdma_base_port;
        int spdk;
        int huge_page;
        int huge_page_reserved;
        int nvme;
        int nvme_stat;
        int ring;

        int crontab;
        int cgroup;
        int cleanlogcore;
        int move_interval;
        uint64_t log_max_bytes;
        int performance_analysis;

        int net_crc;
        int cleanup_thread;
        int storage_area_max_node;
        int force_write_repnum;

        int chunk_rep;
        int localize;
        int writeback;
        int priority;
        int multipath;

        int memcache_seg;
        int memcache_count;

        int control_port;    ///< minirpc
        int data_port;       ///< rpc
        int direct_port;     ///< corerpc
        int lichbd_port;

        int rpc_timeout;
        int offline_timeout;
        int hb_timeout;
        int lease_timeout;
        int master_timeout;
        int polling_timeout;
        int hb_retry;

        char polling_core[MAXSIZE];
        char aio_core[MAXSIZE];
        int main_loop_threads;

        char default_protocol[MAXSIZE];

        int iscsid;
        int nfsd;
        int nvmf;

        int lichbd;
        char lichbd_root[MAXSIZE];
        char lichbd_cache[MAXSIZE];

        // @feature redis cache
        int redis_cache;
        char redis_sock[MAXSIZE];

        int nbd;
        int nbd_port;
        char nbd_sock[MAXSIZE];
        char nbd_root[MAXSIZE];

        int sheepdog;
        int sheepdog_port;
        char sheepdog_sock[MAXSIZE];
        char sheepdog_root[MAXSIZE];

        // for row2 and lsv.
        int bitmap_cache_count;
        int volume_crc;
        int metadata_replica;
        int metadata_consistent;

        uint64_t chunk_cleanup_msgqueue_size;

        int clock;
        int clock_unsafe;
        int clock_mem;
        int etcd_conn;
        int nodata_unsafe;
        int read_modify_write; //read-modify-write

        int background_recovery; //just for debug
        int recovery_interval;   // defaults 8hours
};

int conf_init(void);
int conf_destroy(void);

int get_nfs_export(const char *path, const char *ip, const char *permision);

extern struct sanconf_t sanconf;
extern struct nfsconf_t nfsconf;
extern struct webconf_t webconf;
extern struct mdsconf_t mdsconf;
extern struct cdsconf_t cdsconf;
extern struct gloconf_t gloconf;
extern struct logconf_t logconf;
extern netconf_t netconf;


/*system configure*/
#define LICH_REPLICA_METADATA 3

#define LICH_REPLICA_MIN 2
#define LICH_REPLICA_MAX 6

#define LICH_REPLICA_DEFAULT 3

/*
 * #define FILE_PROTO_EXTERN_ITEM_SIZE (512 / 8)
 * #define CHKINFO_SIZE(__repnum__) (sizeof(chkinfo_t) + sizeof(reploc_t) * __repnum__)
 *
 * sizeof(chkinfo_t) = 40;
 * sizeof(reploc_t) = 4;
 * max = (FILE_PROTO_EXTERN_ITEM_SIZE - sizeof(chkinfo_t)) / sizeof(reploc_t) = (64 - 24) / 4 = 6
 */

#define LICH_METANODE_MAX 10
#define LICH_MASTER_DEFAULT 5
#define LICH_MDINFO_DEFAULT 5
#define LICH_HOSTNAME_MAX 128
#define LICH_HOST_MAX     256

#define LICH_DIRECT_PORT 17902
#define LICH_LICHBD_PORT 17903
#define LICH_RDMA_PORT   19870
#define ISER_LISTEN_PORT 32600
#define LICH_BOARDCAST_PORT 20915

#define LICH_CHUNK_SPLIT        (sizeof(char) * 1024 * 1024 * 1)        /* 1MB */
#define LICH_BLOCK_SPLIT        512
#define LICH_CHK_LEN_MAX        (sizeof(char) * 1024 * 1024 * 64)       /* 64MB */
#define LICH_NODE_SIZE_MAX      ((uint64_t)100 * 1024 * 1024 * 1024 * 1024) /*100TB*/

/**
 * volume single table1 max size in theory: 16000 * 8000 (MB) == 122TB
 * but extend table1 max size in theory: 16000 * 16000 (MB) == 244TB
 * and number of extend table defined with TABLE1_EXT_MAX_NUM
 * so, volume total max size is 122TB + 244TB * 2 = 610TB for now
 */
#define VOLUME_SIZE_MAX ((long long int)512 * 1024 * 1024 * 1024 * 1024) /*512TB*/

#if 0
# define LICH_CHK_LEN_DEF       (sizeof(char) * 1024 * 1024 * 4)        /* 4MB */
#else
#define LICH_CHK_LEN_DEF        (sizeof(char) * 1024 * 1024 * 64)       /* 64MB */
#endif

#if 1
#define LICH_CHK_SPLIT_DEF      (sizeof(char) * 1024 * 1024 * 8)        /* 8MB */
#else
#define LICH_CHK_SPLIT_DEF      (sizeof(char) * 1024 * 1024 * 64)       /* 64MB */
#endif

#if 1
#define JOB_RESUME_DIRECT
#endif

#if 0
#define LATENCY_ANALYSIS
#endif

#if 1
#define IO_FUNC  __attribute__((section(".xiop")))
#else
#define IO_FUNC
#endif

// #if defined(static_assert) /*have static assert*/
#if CMAKE_STATIC_ASSERT
#define HAVE_STATIC_ASSERT
#endif

// node/disk/replica status

#define __S_CLEAN       0x00000000
#define __S_CHECK       0x00000001
#define __S_DIRTY       0x00000002

#define MAX_WAIT_LEN 1024

#define IDLE_THREADS 2

#define SPLIT_MIN 23
#define SPLIT_MAX 27

#define LOCK_TIMEOUT 20
#define LICH_IO_TIMEOUT 25

#define LICH_SPLIT_MAX 20
#define LICH_VM_MAX 1024
#define SCHEDULE_MAX  (LICH_VM_MAX * 2)

#define VOLUME_MAX_CONNECTION 128

// snapshot

#define LICH_VERSION_SNAPTREE 1
#define LICH_SNAPTREE_NEWALGO 1
/* echo -n 'LICH_SNAPDIFF_MAGIC' | md5sum */
#define LICH_SNAPDIFF_MAGIC "39d5946cea6638dbedae44a79a4a2b28"
#define LICH_SNAPDIFF_OFFSET_OFF (strlen(LICH_SNAPDIFF_MAGIC))
#define LICH_SNAPDIFF_SIZE_OFF (LICH_SNAPDIFF_OFFSET_OFF + sizeof(off_t))
#define LICH_SNAPDIFF_BITMAP_OFF (LICH_SNAPDIFF_SIZE_OFF + sizeof(size_t))
#define LICH_SNAPDIFF_HEAD_LEN(len) (LICH_SNAPDIFF_BITMAP_OFF + sizeof(char) * len)

//migrate
#define LICH_MIGRATE_TAG "lich_migrate_tag"

// attrs

#define LICH_SYSTEM           "lich_system"
#define LICH_SYSTEM_ATTR_ROOT "lich_system_root"

#define LICH_SYSTEM_ATTR_NULL "lich_system_null"
#define LICH_SYSTEM_ATTR_NONE "lich_system_none"
#define LICH_SYSTEM_ATTR_AUTO "lich_system_auto"
#define LICH_SYSTEM_ATTR_ROOT "lich_system_root"
#define LICH_SYSTEM_ATTR_CURR "lich_system_curr"
#define LICH_SYSTEM_ATTR_PREFIX "lich_system_"

#define LICH_SYSTEM_ATTR_REPNUM    "lich_system_repnum"
#define LICH_SYSTEM_ATTR_WRITEBACK "lich_system_writeback"
#define LICH_SYSTEM_ATTR_EC        "lich_system_ec"
#define LICH_SYSTEM_ATTR_PRIORITY  "lich_system_priority"
#define LICH_SYSTEM_ATTR_LOCALIZE "lich_system_localize"
#define LICH_SYSTEM_ATTR_MULTIPATH "lich_system_multipath"

// iscsi CHAP
#define LICH_SYSTEM_ATTR_USERNAME  "lich_system_username"
#define LICH_SYSTEM_ATTR_PASSWORD  "lich_system_password"
#define LICH_SYSTEM_ATTR_AUTH      "lich_system_auth"
#define LICH_SYSTEM_ATTR_USERCOUNT "lich_system_usercount"
#define LICH_SYSTEM_ATTR_INITIATOR "lich_system_initiator"
#define LICH_SYSTEM_ATTR_CONNECT_PERMISSION "lich_system_connect_permission"

#define LICH_SYSTEM_ATTR_CREATETIME "lich_system_createtime"
#define LICH_SYSTEM_ATTR_RENAME   "lich_system_rename"
#define LICH_SYSTEM_ATTR_UNLINK   "lich_system_unlink"
#define LICH_SYSTEM_ATTR_VERSION "lich_system_version"
#define LICH_SYSTEM_ATTR_ROLLBACK "lich_system_rollback"
#define LICH_SYSTEM_ATTR_SOURCE   "lich_system_source"
#define LICH_SYSTEM_ATTR_RENAME_LOCK "lich_system_rename_lock"

#define LICH_SYSTEM_ATTR_ROLLBACK_BP "lich_system_rollback_breakpoint"
#define LICH_SYSTEM_ATTR_FLAT_BP "lich_system_flat_breakpoint"

#define LICH_SYSTEM_ATTR_SPARE_WARN  "lich_system_spare_warn"
#define LICH_SYSTEM_ATTR_SPARE_ERROR "lich_system_spare_error"

#define LICH_SYSTEM_ATTR_STORAGE_AREA "lich_system_storage_area"

#define LICH_SYSTEM_ATTR_VFM "lich_system_vfm"

#define VFM_MAX 256

// QoS
#define LICH_SYSTEM_ATTR_THROT_IOPS  "lich_system_throt_iops"
#define LICH_SYSTEM_ATTR_THROT_BW    "lich_system_throt_bw"
#define LICH_SYSTEM_ATTR_LATENCY     "lich_system_latency"

// volume locker
#define LICH_SYSTEM_ATTR_LOCK "__LOCK__"

#define LICH_SYSTEM_ATTR_VAAI     "lich_system_vaai"
#define LICH_SYSTEM_ATTR_THIN     "provisioning"        //defined by Mr. wang
#define LICH_SYSTEM_ATTR_SCSI_ID     "scsi_id"

// lun auth
#define LICH_SYSTEM_ATTR_IP        "lich_system_ip"
#define INITIATOR "initiator"
#define INITIATOR_COUNT "initiatorCount"
#define IQN_MAX_LEN     (72)

//snap
#define TABLE_PRORO_SNAP_MAX      500
#define TABLE_PROTO_USER_SNAP_MAX 256

//

#define ROOT          "/"
#define NFS_ROOT      "/nfs"
#define FUSE_ROOT     "/fuse"
#define ISCSI_ROOT    "/iscsi"
#define SYSTEM_ROOT   "/system"
#define UNLINK_ROOT   "/system/unlink"
#define RMSNAP_ROOT   "/system/rmsnap"
#define ROLLBACK_ROOT "/system/rollback"
#define FLAT_ROOT     "/system/flat"
#define NODELIST_PATH "/tmp"
#define POOLLIST_PATH "/tmp"

#define SHM_ROOT "/dev/shm/lich4"

#define BUF_SIZE_4K     (1024 * 4)
#define BUF_SIZE_8K     (1024 * 8)
#define BUF_SIZE_16K    (1024 * 16)
#define BUF_SIZE_32K    (1024 * 32)
#define BUF_SIZE_64K    (1024 * 64)
#define BUF_SIZE_128K   (1024 * 128)

#define BUF_LEN         BUF_SIZE_4K
#define MAX_BUF_LEN     BUF_SIZE_4K
#define BUF_128         BUF_SIZE_128K

#define DEFAULT_STACK_SIZE BUF_SIZE_64K
#define KEEP_STACK_SIZE (1024)

#define BUFFER_SEG_SIZE (1024 * 1024)

#define MAX_MSG_SIZE (4096)
#define UUID_LEN        (64)

#define UUID_FILE_TIMEOUT (60 * 30)

#define SO_XMITBUF (1024 * 1024 * 1000)     /* 1000MB */

#define SEC_PER_MIN                 (60)
#define SEC_PER_HOU                 (60 * 60)
#define SEC_PER_DAY                 (60 * 60 * 24)

#define MSEC_PER_SEC                (1000)
#define USEC_PER_SEC                (1000 * 1000)
#define USEC_PER_MIN                ((LLU)USEC_PER_SEC * SEC_PER_MIN)
#define USEC_PER_HOU                ((LLU)USEC_PER_SEC * SEC_PER_HOU)
#define USEC_PER_DAY                ((LLU)USEC_PER_SEC * SEC_PER_DAY)

#define SECTOR_SIZE (512)
#define K2B (1024L)
#define M2B (1024 *1024L)
#define G2B (1024 * 1024 *1024L)

#define SOCKID_NORMAL 10
#define SOCKID_CORENET 20

#define HSM_UPDATE_INTERVAL (60 * 30)

#define LICHBD_DEFAULT_NS "default"

#define SD_DEFAULT_PORT 7000
#define SD_DEFAULT_SOCK "/tmp/sheepdog.socket"
#define SD_DEFAULT_ROOT "default"

#define NBD_DEFAULT_PORT  10809
#define NBD_DEFAULT_SOCK "/tmp/nbd-socket"
#define NBD_DEFAULT_ROOT "nbd"

#define REDIS_DEFAULT_SOCK "/tmp/redis.sock"

#define REDIS_

#define REDIS_GROUP 10

#define IO_WARN ((gloconf.rpc_timeout / 2) * 1000 * 1000)

#define MAX_CHUNK_DEFAULT (1024 * 1024 * 10)

// conf variables
int var_set(const char *key, const char *value, int type);
int var_get(const char *key, char *value);
int var_get_type(const char *key, int *type);
void conf_dump();

#if 1
#define RPC_ASSERT
#endif

#define CHUNK_CLEANUP_MSGQUEUE_DEFAULT_SIZE ((LLU)1024*1024*1024*10) //10G 能放30T chunk)

typedef enum {
        VOLUME_FORMAT_RAW  = 0,
        VOLUME_FORMAT_LSV  = 1,
        VOLUME_FORMAT_ROW2 = 2,
        VOLUME_FORMAT_ROW3 = 3,
} volume_format_t;
#define VOLUME_FORMAT_LSV_BEGIN VOLUME_FORMAT_LSV      //must take care of above.
#define VOLUME_FORMAT_LSV_END VOLUME_FORMAT_ROW3
#define IS_RICH_LSV(x) (x >= VOLUME_FORMAT_LSV_BEGIN && x <= VOLUME_FORMAT_LSV_END)

static inline int is_root_snap(const char *name) {
        return strcmp(name, LICH_SYSTEM_ATTR_ROOT) == 0;
}

static inline int is_auto_snap(const char *name) {
        return memcmp(name, LICH_SYSTEM_ATTR_AUTO, strlen(LICH_SYSTEM_ATTR_AUTO)) == 0;
}

static inline int is_deleted_snap(const char *name) {
        return memcmp(name, LICH_SYSTEM_ATTR_UNLINK, strlen(LICH_SYSTEM_ATTR_UNLINK)) == 0;
}

#endif
